home *** CD-ROM | disk | FTP | other *** search
- /* RSPF - Radio Shortest Path First
- * This code may be used for non-commercial purposes only.
- * Anders Klemets SM0RGV
- * 890918 - Version 2.0
- * 900816 - Version 2.1
- *
- * Mods by PA0GRI
- */
- #include "global.h"
- #include "mbuf.h"
- #include "proc.h"
- #include "netuser.h"
- #include "internet.h"
- #include "pktdrvr.h"
- #include "arp.h"
- #include "icmp.h"
- #include "rspf.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: rspf.c,v 1.23 1997/09/07 21:18:28 root Exp root $";
- #endif
-
- #ifdef RSPF
-
- #ifndef AX25
- static struct lq *al_lookup (struct iface *ifp, char *addr, int sort);
- #endif /* AX25 */
-
- struct rspf_stat Rspf_stat = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- struct rspfreasm *Rspfreasmq = NULLRREASM;
- struct rspfiface *Rspfifaces = NULLRIFACE;
- struct rspfadj *Adjs = NULLADJ;
- struct rspfrouter *Rspfrouters = NULLRROUTER;
- struct mbuf *Rspfinq = NULLBUF;
- struct timer Rspfreasmt, Susptimer;
- char *Rrh_message = NULLCHAR;
- unsigned short Rspfpingmax = 3;
- static int Keeprouter = 0;
- static int16 Envelopeid = 0;
- static int Nrspfproc = 0;
- static unsigned char Rspfsubseq = 0;
- static short Rspfseq = -32768L + 1;
- static char *findlowroute (uint32 addr, int *low, int add, uint32 * resaddr, int *resbits);
- static void makeroutes (void);
- static void partialupdate (struct rspfrouter *rr, struct mbuf *bp);
- static struct rspfrouter *rr_lookup (uint32 addr);
- static void rr_delete (uint32 addr);
- static struct rspfiface *rtif_lookup (uint32 addr);
- static void rspfcsum (struct mbuf **bpp, uint32 dest);
- static void update_in (struct mbuf *bp, uint32 addr);
- static void node_in (struct mbuf *bp, uint32 addr, int full);
- static void sendonerspf (uint32 addr, uint32 dest);
- static void sendtoall (struct mbuf *bp, int nodecnt, struct rspfiface *riface);
- static void sendupdate (struct mbuf *bp, int nodecnt, uint32 addr);
- static int isnewer (short a, short b);
- static void del_reasm (struct rspfreasm *re);
- static void reasmtimeout (void *t);
- static struct mbuf *rspfreasm (struct mbuf *bp, struct rspfpacketh *rph, uint32 addr);
- static struct mbuf *fragmenter (struct mbuf *bp, int nodes, int16 mtu);
- static struct mbuf *makeadjupdate (uint32 addr, struct rspfrouter *rr);
- static void pushadj (struct mbuf **bpp, uint32 addr, int bits);
- static void sendrrh (struct rspfiface *ri);
- static void sendrspf (void);
- static void goodbadnews (struct rspfadj *adj);
- static void add_rspfadj (struct rspfadj *adj);
- static void rspfcheck (struct rspfadj *adj);
- static void rspfping (int oldstate, void *p, void *v);
-
-
-
- /* IP passes its RSPF packets to this function */
- void
- rspf_input (struct iface *iface, struct ip *ip, struct mbuf *bp, int rxbroadcast OPTIONAL)
- {
- struct pseudo_header ph;/* Pseudo-header for checksumming */
-
- if (bp == NULLBUF)
- return;
- if (Rspfifaces == NULLRIFACE) { /* Rspf main loop is not running */
- free_p (bp);
- return;
- }
- ph.length = ip->length - IPLEN - ip->optlen;
- ph.source = ip->source;
- ph.dest = ip->dest;
- ph.protocol = ip->protocol;
- if (cksum (&ph, bp, ph.length) != 0) {
- /* Checksum failed, ignore packet completely */
- free_p (bp);
- ++Rspf_stat.badcsum;
- return;
- }
- bp = pushdown (bp, 1 + sizeof (ip->source) + sizeof (iface));
- *bp->data = RSPFE_PACKET;
- memcpy (bp->data + 1, &ip->source, sizeof (ip->source));
- memcpy (bp->data + 1 + sizeof (ip->source), &iface, sizeof (iface));
- enqueue (&Rspfinq, bp);
- }
-
-
-
- /* Main loop in RSPF process */
- void
- rspfmain (int v OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
- {
- union rspf rspf; /* Internal packet structure */
- struct rspfadj *adj = NULLADJ; /* Adjacency */
- struct mbuf *bp, *tbp;
- struct rspfiface *riface;
- struct iface *iface = NULLIF;
- struct route *rp;
- uint32 source; /* Source address */
- int cmd;
-
- for ( ; ; ) {
- if (Rspfinq == NULLBUF)
- kwait (&Rspfinq);
- bp = dequeue (&Rspfinq); /* at least 5 bytes */
- cmd = PULLCHAR (&bp); /*lint !e506 * get internal event indicator */
- (void) pullup (&bp, (unsigned char *) &source, sizeof (source));
- switch (cmd) {
- case RSPFE_RRH:
- sendrrh ((struct rspfiface *) source);
- break;
- case RSPFE_CHECK:
- rspfcheck ((struct rspfadj *) source);
- break;
- case RSPFE_UPDATE:
- sendrspf ();
- break;
- case RSPFE_ARP:
- adj = (struct rspfadj *) source;
- source = adj->addr; /* fall through */
- case RSPFE_PACKET:
- (void) pullup (&bp, (unsigned char *) &iface, sizeof (iface));
- break;
- default:
- break;
- }
- if (cmd != RSPFE_PACKET && cmd != RSPFE_ARP)
- continue;
- if (cmd == RSPFE_PACKET && ntohrspf (&rspf, &bp) == -1) {
- free_p (bp);
- continue;
- }
- if (iface != NULLIF) {
- for (riface = Rspfifaces; riface != NULLRIFACE; riface =
- riface->next)
- if (riface->iface == iface)
- break;
- } else /* fails if there is no route or no RSPF interface */
- riface = rtif_lookup (source);
-
- if (riface == NULLRIFACE) {
- free_p (bp);
- if (cmd == RSPFE_PACKET)
- ++Rspf_stat.norspfiface;
- continue; /* We do not use RSPF on this interface */
- }
- /* If we dont have an entry in the routing table for this station,
- * or if the entry is less than 32 bits specific or has a higher
- * cost than our new route, and is pointing to the wrong interface,
- * then add a correct, private, route.
- */
- rp = rt_lookup (source);
- if (rp == NULLROUTE || (rp != NULLROUTE && rp->iface !=
- riface->iface && (rp->bits < 32 || rp->metric >
- riface->quality))) {
- rp = rt_add (source, 32, 0, iface, riface->quality, 0, 1);
- if (rp != NULLROUTE)
- set_timer (&rp->timer, MSPTICK); /* IT9LTA: dummy value, indicates non-manual route */
- }
- if (cmd == RSPFE_ARP) {
- if (adj != NULLADJ) {
- adj->cost = riface->quality; /* default cost */
- add_rspfadj (adj);
- continue;
- }
- }
- switch (rspf.hdr.type) { /* packet types */
- case RSPF_RRH:
- ++Rspf_stat.rrhin;
- free_p (bp);
- adj = (struct rspfadj *) callocw (1, sizeof (struct rspfadj));
-
- adj->addr = rspf.rrh.addr;
- adj->seq = rspf.rrh.seq;
- adj->cost = riface->quality; /* Default cost */
- adj->state = RSPF_TENTATIVE;
- if (rspf.rrh.flags & RSPFMODE)
- adj->tos = DELAY;
- else
- adj->tos = RELIABILITY;
- add_rspfadj (adj);
- break;
- case RSPF_FULLPKT:
- ++Rspf_stat.updatein;
- /* Feed the packet through the reassembly queue */
- if ((tbp = rspfreasm (bp, &rspf.pkthdr, source)) != NULLBUF)
- update_in (tbp, source);
- break;
- default:
- break;
- }
- }
- }
-
-
-
- /* This function is called every time an RRH should be broadcasted.
- * An RRH is sent on the interface given by ri or on every RSPF interface.
- * The broadcast address of the interface must be routed onto the same
- * interface (using a static route for instance) otherwise there will be no
- * RRH sent on that interface.
- */
- static void
- sendrrh (struct rspfiface *ri) /* interface to use, if specified */
- {
- struct pseudo_header ph;
- struct mbuf *bp, *data = NULLBUF;
- struct rspfiface *riface;
- struct route *rp;
- struct rrh rrh;
-
- for (riface = Rspfifaces; riface != NULLRIFACE; riface = riface->next) {
- if (ri != NULLRIFACE && riface != ri)
- continue;
- if ((rp = rt_lookup (riface->iface->broadcast)) != NULLROUTE &&
- rp->iface == riface->iface) {
- rrh.version = RSPF_VERSION;
- rrh.addr = riface->iface->addr;
- ph.length = 0;
- if (Rrh_message != NULLCHAR) {
- data = ambufw ((int16) strlen (Rrh_message));
- memcpy (data->data, Rrh_message, strlen (Rrh_message));
- ph.length = data->cnt = (int16) strlen (Rrh_message);
- }
- ph.length += RRHLEN;
- ph.source = riface->iface->addr;
- ph.dest = riface->iface->broadcast;
- ph.protocol = RSPF_PTCL;
- /* Start the RRH link level packet counter at 1, since adj->seq
- * is 0 only for ARP generated adjacencies. This is also correct
- * since rawsndcnt will increase by one when the RRH is sent.
- */
- rrh.seq = (int16) riface->iface->rawsndcnt + 1;
- /* Default is to use the same mode as the interface */
- if (Rspfownmode == -1)
- rrh.flags = !(riface->iface->flags & CONNECT_MODE);
- else
- rrh.flags = !(Rspfownmode & CONNECT_MODE);
-
- bp = htonrrh (&rrh, data, &ph);
- ++Rspf_stat.rrhout;
- (void) ip_send (riface->iface->addr, riface->iface->broadcast, RSPF_PTCL,
- 0, 2, bp, 0, 0, 0); /* the ttl will be decremented to 1 */
- }
- }
- }
-
-
-
- /* This function is called whenever an RRH packet has been received or when
- * a new entry is added to the ARP table.
- */
- static void
- add_rspfadj (struct rspfadj *adj)
- {
- struct rspfadj *oldadj, *tmp;
- struct rspfiface *riface;
- struct arp_tab *atp;
- struct lq *alp;
- int dif, origdif;
-
- if (adj == NULLADJ)
- return; /* sanity but it happens... */
- if (ismyaddr (adj->addr)) /*is it my RRH (ie, heard my own bcst)? N8RAW */
- return;
- /* Find the previous copy of the adjacency, if there was any */
- /* Insert the new adjacency */
- adj->next = Adjs;
- Adjs = adj;
- for (oldadj = Adjs; oldadj->next != NULLADJ; oldadj = oldadj->next)
- if (oldadj->next->addr == adj->addr) {
- tmp = oldadj->next;
- oldadj->next = oldadj->next->next;
- oldadj = tmp;
- break;
- }
- if (oldadj->addr != adj->addr || oldadj == adj)
- oldadj = NULLADJ;
-
- /* ARP entries give no sequence number, so save the old one */
- if (oldadj != NULLADJ) {
- if (adj->seq == 0)
- adj->seq = oldadj->seq;
- if (adj->tos == 0)
- adj->tos = oldadj->tos; /* they give no TOS either */
- }
- switch (adj->state) {
- case RSPF_TENTATIVE:
- if (oldadj != NULLADJ) {
- /* If the adjacency was in OK state, it will remain there.
- * An RRH or ARP upcall can never generate an OK -> Tentative
- * transition.
- */
- if (oldadj->state == RSPF_OK)
- adj->state = RSPF_OK;
- adj->okcnt = oldadj->okcnt;
- /* If old state was Bad, don't announce this adjacency until
- * it is known to be OK, to prevent announcing an adjacency
- * with an state transition loop such as OK -> Suspect -> Bad ->
- * Tentative -> Suspect -> Bad -> Tentative -> ...
- */
- if (oldadj->state == RSPF_BAD) {
- adj->okcnt = 0;
- stop_timer (&oldadj->timer);
- /* Enter Suspect state at once, there is no point in
- * dwelling as Tentative.
- */
- rspfcheck (adj);
- } else {
- /* Inherit the old timer */
- adj->timer.func = rspfevent;
- adj->timer.arg = (void *) &adj->timer;
- /* continue where the old timer is stopped */
- adj->timer.duration = oldadj->timer.duration;
- stop_timer (&oldadj->timer);
- /* Set the timer to Suspectimer in the unlikely event that
- * the timer was stopped and oldadj is not Suspect or Bad.
- * Suspect state is dealt with further below.
- */
- if (dur_timer (&adj->timer) == 0L)
- set_timer (&adj->timer, dur_timer (&Susptimer));
- start_detached_timer (&adj->timer);
- set_timer (&adj->timer, dur_timer (&oldadj->timer));
- }
- /* We must now try to figure out from which AX.25 callsign this
- * packet came. Looking at the ARP table may sometimes help.
- */
- if (oldadj->seq != 0 && adj->seq != 0 &&
- (riface = rtif_lookup (adj->addr)) != NULLRIFACE &&
- (atp = arp_lookup (ARP_AX25, adj->addr, riface->iface)) != NULLARP &&
- atp->state == ARP_VALID &&
- (alp = al_lookup (riface->iface, atp->hw_addr, 0)) != NULLLQ) {
- /* The wrapping of the modulus is taken into account here */
- if (oldadj->seq > (MAXINT16 - 100) && adj->seq < 100)
- origdif = adj->seq + MAXINT16 - oldadj->seq;
- else
- origdif = adj->seq - oldadj->seq;
- if ((alp->currxcnt - adj->heard) > (MAXINT16 - 100)
- && adj->seq < 100)
- dif = (int) (origdif + MAXINT16 - (alp->currxcnt - adj->heard));
- else
- dif = (int) (origdif - (alp->currxcnt - adj->heard));
- adj->heard = alp->currxcnt; /* Update the counter */
- /* At this point, "origdif" equals the difference in sequence
- * numbers between the two latest RRH packets, i.e. the
- * number of AX.25 frames the station has sent during since
- * the last RRH packet we heard. "dif" equals the number of
- * AX.25 frames that we actually heard from that station
- * during the same period.
- */
- if (origdif > 0 && dif > 0)
- /* This algorithm can be improved, see 2.1 spec */
- adj->cost = uchar(riface->quality * 2 - riface->quality * dif / origdif);
- }
- /* Ignore any new RRH's if a pinger process is already running */
- if (oldadj->state == RSPF_SUSPECT) {
- if (adj->heard != 0) /* save new heard count */
- oldadj->heard = adj->heard;
- oldadj->next = adj->next; /* adj is at start of chain */
- Adjs = oldadj;
- stop_timer (&adj->timer);
- free ((char *) adj);
- return;
- }
- } else {/* oldadj == NULLADJ */
- rspfcheck (adj); /* enter Suspect state */
- /* A new adjacency may affect the routing table even though no
- * routing updates have yet been received from it.
- */
- makeroutes ();
- }
- break;
- case RSPF_OK:
- if (oldadj != NULLADJ) {
- adj->okcnt += oldadj->okcnt; /* Do these before possible */
- stop_timer (&oldadj->timer); /* killproc() -- KZ1F */
- if (oldadj->state == RSPF_SUSPECT) {
- killproc (oldadj->pinger);
- --Nrspfproc; /* Bug fix - N1BEE */
- }
- } else
- makeroutes (); /* routing table may change */
- if (adj->okcnt == 1) /* A previously unkown route */
- goodbadnews (adj); /* ..that is good news */
- break;
- default:
- break;
- }
- if (oldadj) {
- stop_timer (&oldadj->timer); /* stop timer before free() -- KZ1F */
- #ifndef KZ1F
- free ((char *) oldadj);
- #endif
- }
- }
-
-
-
- /* Take appropriate action if an adjacency is Bad or Tentative */
- static void
- rspfcheck (struct rspfadj *adj)
- {
- struct rspfadj *prev;
-
- for (prev = Adjs; prev != NULLADJ; prev = prev->next)
- if (prev->next == adj)
- break;
- switch (adj->state) {
- case RSPF_OK:
- adj->state = RSPF_TENTATIVE; /* note fall-thru */
- case RSPF_TENTATIVE:
- if (Nrspfproc < RSPF_PROCMAX) {
- Nrspfproc++;
- adj->pinger = newproc ("RSPF ping", 1024, rspfping,
- (int) adj->state, adj, NULL, 0);
- adj->state = RSPF_SUSPECT; /* The adjacency is now Suspect */
- } else {/* Try later */
- set_timer (&adj->timer, dur_timer (&Susptimer));
- start_detached_timer (&adj->timer);
- }
- break;
- case RSPF_BAD:
- rr_delete (adj->addr);
- adj->cost = 255;
- if (adj->okcnt != 0)
- goodbadnews (adj); /* This is bad news... */
- if (prev != NULLADJ)
- prev->next = adj->next; /* Unlink */
- else
- Adjs = adj->next;
- stop_timer (&adj->timer); /* just in case */
- free ((char *) adj); /* delete the adjacency */
- makeroutes (); /* update the routing table */
- break;
- default:
- break;
- }
- }
-
-
-
- /* Send a ping to a suspect or tentative adjacency */
- static void
- rspfping (int oldstate, void *p, void *v OPTIONAL)
- {
- int s, fromlen, pcnt;
- struct icmp icmp;
- struct rspfadj *adj;
- struct sockaddr_in from;
- struct mbuf *bp;
-
- (void) kpause (((ptol (p) & 7) + 1) * 1000L); /* Pause for 1 to 8 seconds */
- adj = (struct rspfadj *) p;
- adj->timer.func = rspfevent; /* Fill in timer values */
- adj->timer.arg = (void *) &adj->timer;
- set_timer (&adj->timer, dur_timer (&Susptimer));
- if ((s = socket (AF_INET, SOCK_RAW, ICMP_PTCL)) == -1) {
- --Nrspfproc;
- adj->state = (char) oldstate;
- start_detached_timer (&adj->timer);
- return;
- }
- fromlen = sizeof (from);
- for (pcnt = 0; pcnt < Rspfpingmax; ++pcnt) {
- pingem (s, adj->addr, 0, (int16) s, 0);
- /* Now collect the reply */
- kalarm (60 * 1000L); /* Let each ping timeout after 60 seconds */
- for ( ; ; ) {
- if (recv_mbuf (s, &bp, 0, (char *) &from, &fromlen) == -1) {
- if (errno == EALARM) { /* We timed out */
- break;
- }
- kalarm (0);
- adj->state = (char) oldstate;
- close_s (s);
- --Nrspfproc;
- start_detached_timer (&adj->timer);
- return;
- }
- (void) ntohicmp (&icmp, &bp);
- free_p (bp);
- if (icmp.type != ICMP_ECHO_REPLY || from.sin_addr.s_addr !=
- (unsigned long) adj->addr || icmp.args.echo.id != s)
- /* Ignore other people's responses */
- continue;
- kalarm (0);
- if (++adj->okcnt == 1)
- goodbadnews (adj); /* Good news */
- close_s (s);
- --Nrspfproc;
- start_detached_timer (&adj->timer);
- adj->state = RSPF_OK; /* Finally change state */
- return;
- }
- }
- /* we give up, mark the adjacency as bad */
- adj->state = RSPF_BAD;
- close_s (s);
- --Nrspfproc;
- start_detached_timer (&adj->timer);
- }
-
-
-
- /* ARP upcalls come in two flavors: When an ARP Reply has been received, we
- * know for certain that bidirectional communication is possible with the
- * particular station. But when an ARP Request is received, or if an ARP
- * entry is added manually, it has yet to be determined if the link is
- * bidirectional so iface is NULLIF in those cases.
- */
- void
- rspfarpupcall (
- uint32 addr, /* Address being added to ARP table */
- int16 hardware, /* Hardware type */
- struct iface *iface /* Interface used, if known */
- ) {
- struct rspfadj *adj;
- struct mbuf *bp;
- struct rspfiface *riface;
-
- if ((riface = rtif_lookup (addr)) == NULLRIFACE)
- return; /* Not a route to an RSPF interface */
- /* Proceed only if the ARP entry is for a hardware type that is relevant
- * for the interface onto which IP datagrams are routed.
- */
- switch (hardware) {
- case ARP_NETROM:
- if (riface->iface->type != CL_NETROM)
- return;
- break;
- case ARP_AX25:
- if (riface->iface->type != CL_AX25)
- return;
- break;
- case ARP_ETHER:
- if (riface->iface->type != CL_ETHERNET)
- return;
- break;
- case NHWTYPES: /* "Any interface type is ok" type entry */
- default:
- return;
- }
- if ((adj = (struct rspfadj *) callocw (1, sizeof (struct rspfadj))) == NULLADJ)
- return;
-
- adj->addr = addr;
- if (iface == NULLIF) /* A manual ARP entry or Request, may be no-good */
- adj->state = RSPF_TENTATIVE;
- else {
- adj->state = RSPF_OK;
- adj->okcnt++;
- adj->timer.func = rspfevent; /* Fill in timer values */
- adj->timer.arg = (void *) &adj->timer;
- set_timer (&adj->timer, dur_timer (&Susptimer));
- start_detached_timer (&adj->timer);
- }
- if ((bp = alloc_mbuf (1 + sizeof (int32) + sizeof (iface))) == NULLBUF) {
- stop_timer (&adj->timer);
- free ((char *) adj);
- return;
- }
- *bp->data = RSPFE_ARP;
- memcpy (bp->data + 1, (char *) &adj, sizeof (adj));
- memcpy (bp->data + 1 + sizeof (adj), (char *) &iface, sizeof (iface));
- bp->cnt = bp->size;
- enqueue (&Rspfinq, bp);
- }
-
-
-
- /* Called by "route add" command. */
- void
- rspfrouteupcall (
- uint32 addr, /* Address added to routing table */
- unsigned bits, /* Significant bits in address */
- uint32 gateway /* Address of gateway station */
- ) {
- /* We are only interested in 32 bit specific routes that use a
- * gateway. Direct routes will be discovered anyway.
- */
- if (bits != 32 || gateway == 0 || gateway == addr)
- return;
- if (rtif_lookup (addr) == NULLRIFACE) /* not routed onto RSPF interface */
- return;
- rspfarpupcall (addr, NHWTYPES, NULLIF); /* proceed as an "arp add" upcall */
- }
-
-
-
- /* When the suspect timer expires, we scan through the routing table for all
- * manual 32 bit specific routes through a gateway that are not an adjacency,
- * and calls rspfrouteupcall(). A similar thing is done for all manual ARP
- * entries. This will make sure that a station that was not reachable when
- * the "route add" or "arp add" command was executed will eventually be
- * discovered if it joins the network.
- */
- void
- rspfsuspect (void *t OPTIONAL)
- {
- struct rspfadj *adj;
- struct route *rp;
- struct arp_tab *ap;
- int i;
-
- start_detached_timer (&Susptimer); /* restart the timer */
- for (i = 0; i < HASHMOD; i++) /* Check the routing table */
- for (rp = Routes[31][i]; rp != NULLROUTE; rp = rp->next) {
- if ((rp->flags & RTPRIVATE) || dur_timer (&rp->timer) != 0)
- continue; /* not this route */
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- if (adj->addr == rp->target)
- break;
- if (adj == NULLADJ) /* it is not already an adjacency */
- rspfrouteupcall (rp->target, 32, rp->gateway);
- }
- for (i = 0; i < HASHMOD; ++i) /* scan the ARP table */
- for (ap = Arp_tab[i]; ap != NULLARP; ap = ap->next) {
- if (dur_timer (&ap->timer)) /* not a manual entry */
- continue;
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- if (adj->addr == ap->ip_addr)
- break;
- if (adj == NULLADJ) /* not already an adjacency */
- rspfarpupcall (ap->ip_addr, ap->hardware, NULLIF);
- }
- }
-
-
-
- /* This non-layered function peeks at the routing table to figure out to which
- * interface datagrams for addr will be routed. Then it returns the matching
- * rspfiface structure.
- */
- static
- struct rspfiface *
- rtif_lookup (uint32 addr)
- {
- struct rspfiface *riface;
- struct route *rp;
-
- if ((rp = rt_lookup (addr)) == NULLROUTE)
- return NULLRIFACE;
- riface = Rspfifaces;
- while (riface != NULLRIFACE) {
- if (riface->iface == rp->iface)
- return riface;
- riface = riface->next;
- }
- return NULLRIFACE;
- }
-
-
-
- /* Send good or bad news partial routing updates. A cost of 255 should be
- * interpreted as bad news by the remote station.
- */
- static void
- goodbadnews (struct rspfadj *adj)
- {
- struct rspfnodeh nodeh;
- struct rspflinkh linkh;
- struct rspfiface *riface;
- struct rspfrouter *rr;
- struct mbuf *bp, *tbp, *wbp;
- int nodecnt = 1;
-
- if ((riface = rtif_lookup (adj->addr)) == NULLRIFACE)
- return;
- bp = ambufw (5);
- bp->cnt = bp->size;
- *bp->data = 32; /* the number of significant bits in the address */
- (void) put32 (bp->data + 1, adj->addr);
- linkh.horizon = riface->horizon;
- linkh.erp = riface->erp;
- linkh.cost = adj->cost;
- linkh.adjn = 1;
- tbp = htonrspflink (&linkh, bp);
- nodeh.seq = Rspfseq;
- nodeh.subseq = ++Rspfsubseq;
- nodeh.links = 1;
- for (riface = Rspfifaces; riface != NULLRIFACE; riface = riface->next) {
- if (dup_p (&wbp, tbp, 0, len_p (tbp)) != len_p (tbp)) {
- free_p (wbp);
- continue;
- }
- nodeh.addr = riface->iface->addr;
- bp = htonrspfnode (&nodeh, wbp);
- sendtoall (bp, 1, riface);
- }
- free_p (tbp);
- /* If this is a new adjacency, then send it a routing update immediately */
- if (adj->cost == 255 || adj->okcnt != 1)
- return;
- /* When two RSPF stations learn about each others existence, one of
- * them will usually have received an RRH from the other. The one that
- * received the RRH will send the peer a routing update immediately.
- * So in the code below, if no RRH has been received (seq is 0) and no
- * routing update has yet been received, we should expect to receive a
- * routing update shortly if the adjacency is running RSPF.
- * This could fail though if two RSPF stations learn about each other
- * solely through ARP upcalls and no RRH's or Updates were exchanged
- * prior to or during the establishment of the adjacency.
- */
- if (adj->seq == 0 && rr_lookup (adj->addr) == NULLRROUTER) {
- if (adj->state != RSPF_SUSPECT) /* running in RSPF process, give up */
- return;
- kalarm (15 * 1000); /* wait for an Update */
- if (kwait (adj) == EALARM)
- return; /* still no sign of RSPF activity from the adjacency */
- kalarm (0);
- }
- ++adj->okcnt; /* we don't want to get here again */
- if ((bp = makeownupdate (adj->addr, 1)) == NULLBUF)
- return;
- for (rr = Rspfrouters; rr != NULLRROUTER; rr = rr->next)
- if ((tbp = makeadjupdate (get32 ((char *) rr->data->data), rr)) != NULLBUF) {
- append (&bp, tbp);
- nodecnt++;
- }
- sendupdate (bp, nodecnt, adj->addr);
- }
-
-
-
- /* This function is called whenever it is time to send a new RSPF update */
- static void
- sendrspf (void)
- {
- struct rspfrouter *rr;
- struct mbuf *bp, *wbp, *tmp = NULLBUF;
- struct rspfiface *riface;
- struct rspfadj *adj;
- int nodecnt, incr = 1;
-
- for (nodecnt = 1, rr = Rspfrouters; rr != NULLRROUTER; rr = rr->next)
- if (!rr->sent) /* don't send stale data */
- if ((bp = makeadjupdate (get32 ((char *) rr->data->data), rr)) != NULLBUF) {
- append (&tmp, bp);
- nodecnt++;
- }
- for (riface = Rspfifaces; riface != NULLRIFACE; riface = riface->next) {
- /* Find an address that is routed onto this interface */
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- if (rtif_lookup (adj->addr) == riface)
- break;
- if (adj == NULLADJ) /* no adjacency on that interface? */
- continue;
- if (dup_p (&wbp, tmp, 0, len_p (tmp)) != len_p (tmp)) {
- free_p (wbp);
- continue;
- }
- if ((bp = makeownupdate (adj->addr, incr)) != NULLBUF) {
- incr = 0; /* sequence number is incremented only once */
- append (&bp, wbp);
- } else
- break;
- sendtoall (bp, nodecnt, riface);
- }
- free_p (tmp);
- for (rr = Rspfrouters; rr != NULLRROUTER; rr = rr->next)
- if (!rr->sent) /* Mark router data as propagated */
- ++rr->sent;
- }
-
-
-
- /* This function is used to answer "poll" messages */
- static void
- sendonerspf (
- uint32 addr, /* address of station whose routing update we will make */
- uint32 dest /* address of station to send the update to */
- ) {
- struct mbuf *bp;
-
- if (ismyaddr (addr)) {
- if ((bp = makeownupdate (dest, 0)) == NULLBUF)
- return;
- sendupdate (bp, 1, dest);
- return;
- }
- if ((bp = makeadjupdate (addr, NULLRROUTER)) == NULLBUF)
- return;
- sendupdate (bp, 1, dest);
- }
-
-
-
- /* send an update to all adjacencies on an RSPF interface */
- static void
- sendtoall (
- struct mbuf *bp,
- int nodecnt, /* number of reporting nodes in update */
- struct rspfiface *riface /* interface to sent to */
- ) {
- struct rspfadj *adj;
- struct mbuf *wbp;
- int broad;
-
- for (broad = 0, adj = Adjs; adj != NULLADJ; adj = adj->next)
- /* If adj->seq is 0 we have never received an RRH from the
- * adjacency, and if there is no stored routing update, then
- * it is not known if the adjacency understands RSPF.
- */
- if ((adj->seq != 0 || rr_lookup (adj->addr) != NULLRROUTER) &&
- riface == rtif_lookup (adj->addr)) {
- if ((adj->tos & RELIABILITY) && !(adj->tos & DELAY)) {
- if (dup_p (&wbp, bp, 0, len_p (bp)) != len_p (bp)) {
- free_p (wbp);
- continue;
- }
- sendupdate (wbp, nodecnt, adj->addr); /* private copy */
- } else
- ++broad; /* send to broadcast IP address instead */
- }
- if (broad != 0)
- if (dup_p (&wbp, bp, 0, len_p (bp)) != len_p (bp))
- free_p (wbp);
- else
- sendupdate (wbp, nodecnt, riface->iface->broadcast);
- free_p (bp);
- }
-
-
-
- /* This function sends a routing update to the adjacencies that we have
- * recevied RRH's from.
- */
- static void
- sendupdate (
- struct mbuf *bp, /* Full packet, except for the packet header */
- int nodecnt, /* Number of reporting nodes in the packet */
- uint32 addr /* Station to send update to */
- ) {
- struct rspfadj *adj;
- struct mbuf *tmp;
- int tos = 0;
-
- /* See if we are sending to a known adjacency, in use its TOS in
- * that case.
- */
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- if (adj->addr == addr) {
- tos = adj->tos;
- break;
- }
- if ((tmp = fragmenter (bp, nodecnt, ip_mtu (addr) - IPLEN)) == NULLBUF)
- return;
- while ((bp = dequeue (&tmp)) != NULLBUF) {
- rspfcsum (&bp, addr); /* Calculate the checksum */
- ++Rspf_stat.updateout;
- (void) ip_send (INADDR_ANY, addr, RSPF_PTCL, (char) (INET_CTL | tos), 2, bp, 0, 0, 0);
- }
- return;
- }
-
-
-
- /* Fragment a large mbuf if necessary into packets of maximum mtu bytes.
- * Each packet is prepended a RSPF routing update header, without the checksum.
- */
- static struct mbuf *
- fragmenter (
- struct mbuf *bp, /* packet to send, without packet header */
- int nodes, /* The number of reporting nodes in the routing update */
- int16 mtu /* The maximum transmission unit */
- ) {
- struct rspfnodeh nodeh;
- struct rspflinkh linkh;
- struct rspfpacketh pkth;
- struct mbuf *tbp, *tmp, *bpq = NULLBUF;
- int n, nodecnt, linkcnt, adjcnt, nodemax, thesync;
- char *cp = NULLCHAR, fragn = 1;
-
- if (mtu < RSPFPKTLEN + RSPFNODELEN || bp == NULLBUF) {
- free_p (bp);
- return NULLBUF;
- }
- ++Envelopeid;
- nodemax = nodes; /* total number of nodes in envelope */
- nodecnt = nodes; /* nodes left to packetize */
- linkcnt = adjcnt = 0;
-
- while (len_p (bp) != 0) {
- int16 tmpint;
- tmpint = len_p (bp) + RSPFPKTLEN;
- n = min (mtu, tmpint); /* length of this packet */
- n -= RSPFPKTLEN;
- tbp = NULLBUF;
- thesync = 0;
- if (adjcnt) {
- tbp = ambufw ((int16) min (adjcnt * 5, n / 5 * 5));
- tbp->cnt = tbp->size;
- cp = (char *) tbp->data;
- }
- while (n > 0) {
- while (adjcnt) {
- if ((n -= 5) < 0)
- break;
- (void) pullup (&bp, (unsigned char *) cp, 5);
- if (cp)
- cp += 5;
- adjcnt--;
- }
- if (linkcnt && n > 0) {
- if ((n -= RSPFLINKLEN) < 0)
- break;
- (void) ntohrspflink (&linkh, &bp);
- adjcnt = linkh.adjn;
- tmp = htonrspflink (&linkh, NULLBUF);
- append (&tbp, tmp);
- tmp = ambufw ((int16) min (5 * adjcnt, n / 5 * 5));
- tmp->cnt = tmp->size;
- cp = (char *) tmp->data;
- append (&tbp, tmp);
- linkcnt--;
- continue;
- }
- if (nodecnt && linkcnt == 0 && n > 0) {
- if ((n -= RSPFNODELEN) < 0)
- break;
- if (nodecnt == nodes) /* Set the sync octet */
- thesync = len_p (tbp) + 4;
- (void) ntohrspfnode (&nodeh, &bp);
- linkcnt = nodeh.links;
- tmp = htonrspfnode (&nodeh, NULLBUF);
- append (&tbp, tmp);
- nodecnt--;
- }
- }
- pkth.version = RSPF_VERSION; /* The version number */
- pkth.type = RSPF_FULLPKT; /* The packet type */
- pkth.fragn = uchar(fragn++); /* The fragment number */
- pkth.fragtot = 0; /* The total number of fragments */
- pkth.csum = 0; /* The checksum */
- pkth.sync = uchar(thesync < 256 ? thesync : 0); /* The sync octet */
- pkth.nodes = uchar(nodemax); /* The number of nodes in envelope */
- pkth.envid = Envelopeid; /* The envelope-ID */
- tmp = htonrspf (&pkth, tbp); /* add packet header */
- enqueue (&bpq, tmp); /* add packet to chain */
- nodes = nodecnt;/* number of nodes left */
- }
- free_p (bp);
- for (tbp = bpq; tbp != NULLBUF; tbp = tbp->anext)
- *(tbp->data + 3) = uchar(len_q (bpq)); /* Set the fragment total counter */
- return bpq;
- }
-
-
-
- /* Calculate the checksum on an RSPF routing update packet */
- static void
- rspfcsum (struct mbuf **bpp, uint32 dest)
- {
- struct pseudo_header ph;
- int16 thechecksum;
-
- ph.length = len_p (*bpp);
- ph.source = locaddr (dest);
- ph.dest = dest;
- ph.protocol = RSPF_PTCL;
- if ((thechecksum = cksum (&ph, *bpp, ph.length)) == 0)
- /* was thechecksum = 0xffffffff - odd, since it is a int16! */
- thechecksum = 0xffff;
- /* This assumes that the checksum really is at this position */
- (void) put16 ((*bpp)->data + 4, thechecksum);
- }
-
-
-
- /* This function creates our own routing update and returns it in an mbuf */
- struct mbuf *
- makeownupdate (
- uint32 dest, /* Address of a station that will get this update */
- int new /* True if the sequence number should be incremented */
- ) {
- struct rspfadj *adj;
- struct rspflinkh linkh;
- struct rspfnodeh nodeh;
- struct rspfiface *riface, rifdefault;
- struct mbuf *bp = NULLBUF, *tbp, *tmp;
- struct route *rp;
- int i, adjcnt, lnkcnt, bits;
- int32 prev, low, cur;
-
- /* Set default values to apply to non-RSPF interfaces */
- rifdefault.horizon = 32;
- rifdefault.erp = 0;
- rifdefault.quality = 0;
- /* Our adjacencies has to be sorted into groups of the same horizon,
- * ERP factor and cost. This is done by combining these numbers into a
- * single one, modulo 256 and take the lowest number first.
- */
- low = 0;
- lnkcnt = 0;
- for ( ; ; ) {
- prev = low;
- low = 255 * 65536L + 255 * 256 + 255;
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- /* Include all adjacecies that have been or are in OK state
- * in the update. Bad adjacencies are also included to give
- * them a chance to recover. Hopelessly Bad adjacencies are
- * eventually deleted elsewhere.
- */
- if (adj->okcnt != 0 && (riface = rtif_lookup (adj->addr)) !=
- NULLRIFACE) {
- cur = riface->horizon * 65536L + riface->erp * 256 + adj->cost;
- if (cur > prev && cur < low)
- low = cur;
- }
- /* Add any manual public, 1-31 bit specific routes.
- * Use the route metric only if it is greater than the default
- * quality to lessen a possible "wormhole" effect.
- */
- for (bits = 1; bits <= 31; bits++)
- for (i = 0; i < HASHMOD; i++)
- for (rp = Routes[bits - 1][i]; rp != NULLROUTE; rp = rp->next)
- if (!(rp->flags & RTPRIVATE) && !dur_timer (&rp->timer)) {
- if ((riface = rtif_lookup (rp->target)) == NULLRIFACE)
- riface = &rifdefault;
- cur = riface->horizon * 65536L + riface->erp * 256 +
- (rp->metric > riface->quality ? rp->metric :
- riface->quality);
- if (cur > prev && cur < low)
- low = cur;
- }
- /* Add any 32 bit routes on interfaces not using RSPF */
- for (i = 0; i < HASHMOD; i++)
- for (rp = Routes[31][i]; rp != NULLROUTE; rp = rp->next)
- if (!(rp->flags & RTPRIVATE) && rtif_lookup (rp->target)
- == NULLRIFACE) {
- cur = rifdefault.horizon * 65536L + rifdefault.erp * 256 +
- (rp->metric > rifdefault.quality ? rp->metric :
- rifdefault.quality);
- if (cur > prev && cur < low)
- low = cur;
- }
- /* Add the default route */
- if ((rp = rt_blookup (0, 0)) != NULLROUTE && !(rp->flags & RTPRIVATE) &&
- !dur_timer (&rp->timer)) {
- if ((riface = rtif_lookup (0)) == NULLRIFACE)
- riface = &rifdefault;
- cur = riface->horizon * 65536L + riface->erp * 256 +
- (rp->metric > riface->quality ? rp->metric : riface->quality);
- if (cur > prev && cur < low)
- low = cur;
- }
- if (low == 255 * 65536L + 255 * 256 + 255) /* All done */
- break;
- /* now start adding the routes */
- adjcnt = 0;
- tbp = NULLBUF;
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- if (adj->okcnt != 0 && (riface = rtif_lookup (adj->addr)) !=
- NULLRIFACE)
- if (riface->horizon * 65536L + riface->erp * 256 + adj->cost == low) {
- pushadj (&tbp, adj->addr, 32);
- adjcnt++;
- }
- for (bits = 1; bits <= 31; bits++)
- for (i = 0; i < HASHMOD; i++)
- for (rp = Routes[bits - 1][i]; rp != NULLROUTE; rp = rp->next)
- if (!(rp->flags & RTPRIVATE) && !dur_timer (&rp->timer)) {
- if ((riface = rtif_lookup (rp->target)) == NULLRIFACE)
- riface = &rifdefault;
- /* Manually entered local routes only */
- if (riface->horizon * 65536L + riface->erp * 256 +
- (rp->metric > riface->quality ? rp->metric :
- riface->quality) == low) {
- pushadj (&tbp, rp->target, bits);
- adjcnt++;
- }
- }
- for (i = 0; i < HASHMOD; i++) /* 32 bit specific routes */
- for (rp = Routes[31][i]; rp != NULLROUTE; rp = rp->next)
- if (!(rp->flags & RTPRIVATE) && rtif_lookup (rp->target)
- == NULLRIFACE)
- if (rifdefault.horizon * 65536L + rifdefault.erp * 256 +
- (rp->metric > rifdefault.quality ? rp->metric :
- rifdefault.quality) == low) {
- pushadj (&tbp, rp->target, bits);
- adjcnt++;
- }
- /* Add the default route */
- if ((rp = rt_blookup (0, 0)) != NULLROUTE && !(rp->flags & RTPRIVATE) &&
- !dur_timer (&rp->timer)) {
- if ((riface = rtif_lookup (0)) == NULLRIFACE)
- riface = &rifdefault;
- if (riface->horizon * 65536L + riface->erp * 256 + (rp->metric >
- riface->quality ? rp->metric : riface->quality) == low) {
- pushadj (&tbp, 0, 0);
- adjcnt++;
- }
- }
- if (adjcnt != 0) {
- /* Prepend the link header */
- linkh.horizon = ((low >> 16) & 255); /*lint !e704 * Horizon value */
- linkh.erp = ((low >> 8) & 255); /*lint !e704 * ERP factor */
- linkh.cost = (low & 255); /* Link cost */
- linkh.adjn = uchar(adjcnt); /* Number of adjacencies */
- tmp = htonrspflink (&linkh, tbp);
- append (&bp, tmp);
- lnkcnt++;
- }
- }
- /* Prepend the node header */
- if (lnkcnt != 0) {
- /* Set our address to the IP address used on the destinations
- * interface.
- */
- if (dest == INADDR_ANY || (riface = rtif_lookup (dest)) == NULLRIFACE)
- nodeh.addr = Ip_addr;
- else
- nodeh.addr = riface->iface->addr;
- if (new) { /* increase sequence number, clear subseq. number */
- if (Rspfseq == 32768L - 2 || Rspfseq == -32768L + 1)
- Rspfseq = 0; /* wrap around */
- else
- ++Rspfseq;
- Rspfsubseq = 0;
- }
- nodeh.seq = Rspfseq;
- nodeh.subseq = 0;
- nodeh.links = uchar(lnkcnt);
- return htonrspfnode (&nodeh, bp);
- } else {
- free_p (bp);
- return NULLBUF;
- }
- }
-
-
-
- /* Prepends an adjacency to bpp. Allocates bpp in large chunk for efficency */
- static void
- pushadj (struct mbuf **bpp, uint32 addr, int bits)
- {
- if (bpp == NULLBUFP)
- return;
- if (*bpp == NULLBUF) {
- *bpp = ambufw (60); /* good for 12 adjacencies */
- (*bpp)->data += 55;
- (*bpp)->cnt = 5;
- } else
- *bpp = pushdown (*bpp, 5);
- *(*bpp)->data = uchar(bits);
- (void) put32 ((*bpp)->data + 1, addr);
- }
-
-
-
- /* This function returns the latest routing update in network fromat from
- * the adjacency denoted by addr.
- */
- static struct mbuf *
- makeadjupdate (
- uint32 addr,
- struct rspfrouter *rr /* pointer to stored routing entry, if known */
- ) {
- struct mbuf *tmp, *tmp2, *tmp3, *bp = NULLBUF;
- struct rspfnodeh nodeh;
- struct rspflinkh linkh;
- int linkcnt = 0;
-
- if (rr == NULLRROUTER && (rr = rr_lookup (addr)) == NULLRROUTER)
- return NULLBUF;
- if (dup_p (&tmp, rr->data, 0, len_p (rr->data)) != len_p (rr->data)) {
- free_p (tmp);
- return NULLBUF;
- }
- (void) ntohrspfnode (&nodeh, &tmp); /* Get the node header */
- while (nodeh.links--) {
- (void) ntohrspflink (&linkh, &tmp);
- /* Decrement and check the horizon value */
- if (--linkh.horizon > 0) {
- /* Duplicate the adjacencies */
- if (dup_p (&tmp2, tmp, 0, 5 * linkh.adjn) != 5 * linkh.adjn) {
- free_p (tmp);
- free_p (tmp2);
- free_p (bp);
- return NULLBUF;
- }
- /* Prepend the link header */
- tmp3 = htonrspflink (&linkh, tmp2);
- append (&bp, tmp3);
- linkcnt++;
- }
- (void) pullup (&tmp, (unsigned char *)0, 5 * linkh.adjn); /* Skip the adjacencies */
- }
- free_p (tmp);
- if (linkcnt == 0) { /* No links at all? */
- free_p (bp);
- return NULLBUF;
- }
- nodeh.subseq = uchar(rr->subseq);
- nodeh.links = uchar(linkcnt);
- /* Prepend the node header */
- return htonrspfnode (&nodeh, bp);
- }
-
-
-
- /* Returns 1 if sequence number a is newer than b. Sequence numbers start
- * at -32768 + 1 and then continues with 0 and the positive integer numbers
- * until reaching 32768 - 2 after which they continue with 0.
- * Algorithm taken from RFC-1131 but fixed bug when a or b is 0.
- */
- static int
- isnewer (short a, short b)
- {
- if ((b < 0 && a > b) ||
- (a >= 0 && b >= 0 && /* bug corrected here */
- (((32768L - 1) / 2 > (a - b) && (a - b) > 0) ||
- (a - b) < -(32768L - 1) / 2)))
- return 1;
- return 0;
- }
-
-
-
- /* Reassemble possibly fragmented packets into a single large one */
- static struct mbuf *
- rspfreasm (
- struct mbuf *bp, /* Routing update packet without packet header */
- struct rspfpacketh *rph, /* Packet header */
- uint32 addr /* Address of station we got the packet from */
- ) {
- union rspf rspf;
- struct rspfreasm *re, *rtmp;
- struct mbuf *tbp, *bp1, *bp2;
-
- for (re = Rspfreasmq; re != NULLRREASM; re = re->next)
- if (re->addr == addr) { /* found another fragment */
- if (dup_p (&tbp, re->data, 0, RSPFPKTLEN) != RSPFPKTLEN) {
- free_p (tbp);
- free_p (bp);
- return NULLBUF;
- }
- (void) ntohrspf (&rspf, &tbp); /* get its packet header */
- if (rph->envid != rspf.pkthdr.envid) {
- del_reasm (re); /* an obsolete entry, delete it */
- break;
- }
- /* Now try to find a place where this fragment fits in the chain */
- bp1 = re->data;
- bp2 = NULLBUF;
- while (rph->fragn > rspf.pkthdr.fragn && bp1->anext != NULLBUF) {
- bp2 = bp1;
- bp1 = bp1->anext;
- if (dup_p (&tbp, bp1, 0, RSPFPKTLEN) != RSPFPKTLEN) {
- free_p (bp);
- free_p (tbp);
- return NULLBUF;
- }
- (void) ntohrspf (&rspf, &tbp);
- }
- if (rspf.pkthdr.fragn == rph->fragn) {
- free_p (bp);
- return NULLBUF; /* We already had this one */
- }
- bp = htonrspf (rph, bp); /* Put the packet header back on */
- /* Insert the fragment at the right place in the chain */
- if (rph->fragn > rspf.pkthdr.fragn) {
- bp1->anext = bp;
- bp->anext = NULLBUF;
- } else {
- if (bp2 != NULLBUF)
- bp2->anext = bp;
- else
- re->data = bp;
- bp->anext = bp1;
- }
- if (len_q (re->data) == rspf.pkthdr.fragtot) {
- bp1 = NULLBUF; /* we have all the fragments */
- while ((bp2 = dequeue (&re->data)) != NULLBUF) {
- (void) pullup (&bp2, (unsigned char *)0, RSPFPKTLEN); /* strip the headers */
- append (&bp1, bp2); /* and form a single packet */
- }
- del_reasm (re);
- stop_timer (&Rspfreasmt);
- reasmtimeout (NULL); /* restarts timer if necessary */
- return bp1; /* return the completed packet */
- }
- re->time = secclock (); /* Update the timestamp */
- goto timstart; /* We have to wait for fragments */
- }
- /* At this point we know that there is no matching entry in the
- reassembly queue (any more) */
- if (rph->fragtot == 1) /* Simple case, an un-fragmented packet */
- return bp;
- tbp = htonrspf (rph, bp); /* Put the packet header back on */
- rtmp = (struct rspfreasm *) callocw (1, sizeof (struct rspfreasm));
-
- /* The values are filled in */
- rtmp->addr = addr;
- rtmp->time = secclock ();
- rtmp->data = tbp;
- rtmp->next = Rspfreasmq;
- Rspfreasmq = rtmp;
- timstart: /* Start the timer if needed */
- if (!run_timer (&Rspfreasmt)) {
- Rspfreasmt.func = reasmtimeout;
- Rspfreasmt.arg = NULL;
- set_timer (&Rspfreasmt, RSPF_RTIME * 1000L); /* The reassembly timeout */
- start_detached_timer (&Rspfreasmt);
- }
- return NULLBUF;
- }
-
-
-
- /* Delete a reassembly descriptor from the queue */
- static void
- del_reasm (struct rspfreasm *re)
- {
- struct rspfreasm *r, *prev = NULLRREASM;
-
- for (r = Rspfreasmq; r != NULLRREASM; prev = r, r = r->next)
- if (r == re) {
- free_q (&re->data);
- if (prev != NULLRREASM)
- prev->next = re->next;
- else
- Rspfreasmq = re->next;
- free ((char *) re);
- break;
- }
- }
-
-
-
- /* When the reassembly timer times out, this function tries to make use of
- * any fragments in the reassembly queue.
- */
- static void
- reasmtimeout (void *t OPTIONAL)
- {
- union rspf rspf;
- struct rspfreasm *re;
- struct mbuf *bp, *tbp;
- int last = 0;
- int32 low;
-
- re = Rspfreasmq;
- while (re != NULLRREASM)
- if ((secclock () - re->time) >= RSPF_RTIME) {
- /* Try to use what we have */
- bp = NULLBUF;
- while ((tbp = dequeue (&re->data)) != NULLBUF) {
- (void) ntohrspf (&rspf, &tbp);
- if (rspf.pkthdr.fragn != (last + 1)) { /* a missing fragment */
- if (bp != NULLBUF)
- update_in (bp, re->addr);
- bp = NULLBUF;
- if (rspf.pkthdr.sync != 0)
- (void) pullup (&tbp, (unsigned char *)0, rspf.pkthdr.sync - 4);
- else { /* no sync possible in this fragment */
- free_p (tbp);
- continue;
- }
- }
- append (&bp, tbp);
- last = rspf.pkthdr.fragn;
- }
- if (bp != NULLBUF)
- update_in (bp, re->addr);
- del_reasm (re);
- re = Rspfreasmq; /* start over again */
- } else
- re = re->next;
- /* Find the oldest fragment and restart the reassembly timer */
- low = 0;
- for (re = Rspfreasmq; re != NULLRREASM; re = re->next)
- if (re->time < low || low == 0)
- low = re->time;
- if (low) {
- /* KF8NH 1993.01.17: clock() on below line changed to secclock() */
- set_timer (&Rspfreasmt, (RSPF_RTIME - (secclock () - low)) * 1000L);
- if (dur_timer (&Rspfreasmt) > 0) /* just to be safe */
- start_detached_timer (&Rspfreasmt);
- }
- }
-
-
-
- /* Handle incoming routing updates (a reassembled envelope) */
- static void
- update_in (
- struct mbuf *bp, /* Reassembled data packet, without packet header */
- uint32 addr /* Senders address (in host order) */
- ) {
- struct rspfnodeh nodeh;
- struct rspflinkh linkh;
- struct rspfadj *adj;
- struct mbuf *tbp, *tmp, *b;
- int linkcnt = 0, adjcnt = 0;
- int16 offset = 0;
-
- tbp = b = NULLBUF;
- /* Check to see if the sender is an adjacency */
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- if (adj->addr == addr)
- break;
- /* One may argue that updates from non-adjacencies should not be
- * accepted since they will not contribute to the routing table.
- * But it might happen that the sender will very shortly become an
- * adjacency, and then its routing update will come handy. By increasing
- * Keeprouter, routing updates from disjoint routers will not be not be
- * purged when makeroutes() is called this time.
- */
- if (adj == NULLADJ) {
- ++Rspf_stat.noadjupdate;
- Keeprouter += 2;
- } else
- ksignal (adj, 1); /* alert anyone waiting for the update */
- while (offset < len_p (bp)) {
- if (adjcnt) {
- if (dup_p (&tmp, bp, offset, 5) == 5) {
- append (&tbp, tmp);
- offset += 5;
- adjcnt--;
- continue;
- } else
- break;
- }
- if (tbp != NULLBUF) {
- tmp = htonrspflink (&linkh, tbp);
- append (&b, tmp);
- tbp = NULLBUF;
- }
- if (linkcnt) {
- if (dup_p (&tbp, bp, offset, RSPFLINKLEN) == RSPFLINKLEN) {
- (void) ntohrspflink (&linkh, &tbp);
- adjcnt = linkh.adjn;
- offset += RSPFLINKLEN;
- linkcnt--;
- continue;
- } else
- break;
- }
- if (b != NULLBUF) {
- tmp = htonrspfnode (&nodeh, b);
- node_in (tmp, addr, 1); /* a full router update */
- b = NULLBUF;
- }
- if (dup_p (&tmp, bp, offset, RSPFNODELEN) == RSPFNODELEN) {
- (void) ntohrspfnode (&nodeh, &tmp);
- linkcnt = nodeh.links;
- offset += RSPFNODELEN;
- } else {
- free_p (bp);
- free_p (tmp);
- return;
- }
- }
- if (tbp != NULLBUF) {
- /* adjust the adjacency counter in the link header */
- linkh.adjn -= uchar(adjcnt); /*lint !e644 */
- tmp = htonrspflink (&linkh, tbp);
- append (&b, tmp);
- }
- /* adjust the link counter in the node header */
- nodeh.links -= uchar(linkcnt); /*lint !e771 */
- tmp = htonrspfnode (&nodeh, b);
- free_p (bp);
- if (linkcnt || adjcnt)
- node_in (tmp, addr, 0); /* a partial router update */
- else
- node_in (tmp, addr, 1);
- }
-
-
-
- static void
- node_in (
- struct mbuf *bp, /* A single update, starting with the node header */
- uint32 addr, /* Address of station we got packet from */
- int full /* False if we got a partial update */
- ) {
- struct mbuf *tbp;
- struct rspfnodeh nodeh, rnodeh;
- struct rspfrouter *rr;
-
- if (dup_p (&tbp, bp, 0, RSPFNODELEN) != RSPFNODELEN) {
- free_p (bp);
- free_p (tbp);
- return;
- }
- (void) ntohrspfnode (&nodeh, &tbp);
- if (ismyaddr (nodeh.addr)) {
- /* If another station thinks our routing update sequence number is
- * larger than it really is, this might be because we have had
- * a fast system reset and routing updates from the old "epoch"
- * are still present in the network.
- */
- if (isnewer (nodeh.seq, Rspfseq)) {
- Rspfseq = nodeh.seq + 1; /* Catch up */
- if (nodeh.seq == 32768L - 2 || nodeh.seq == -32768L + 1)
- Rspfseq = 0; /* Wrap around */
- sendonerspf (nodeh.addr, addr); /* Send him the latest packet */
- }
- free_p (bp); /* We already know our own adjacencies! */
- return;
- }
- if ((rr = rr_lookup (nodeh.addr)) != NULLRROUTER) {
- if (dup_p (&tbp, rr->data, 0, RSPFNODELEN) != RSPFNODELEN) {
- free_p (bp);
- free_p (tbp);
- return;
- }
- (void) ntohrspfnode (&rnodeh, &tbp);
- if (nodeh.seq == rnodeh.seq && nodeh.subseq <= uchar(rr->subseq)) {
- free_p (bp);
- return; /* We already have this one */
- }
- if (isnewer (rnodeh.seq, nodeh.seq)) {
- /* Send him the latest packet */
- sendonerspf (nodeh.addr, addr);
- free_p (bp);
- ++Rspf_stat.oldreport;
- return;
- }
- if (nodeh.subseq > uchar(rr->subseq) && nodeh.seq == rnodeh.seq) {
- rr->subseq = (char) nodeh.subseq;
- partialupdate (rr, bp);
- makeroutes ();
- return;
- }
- if (isnewer (nodeh.seq, rnodeh.seq) && !full) {
- partialupdate (rr, bp);
- makeroutes ();
- /* Send a "poll" packet */
- --nodeh.seq;
- nodeh.subseq = 0;
- nodeh.links = 0;
- tbp = htonrspfnode (&nodeh, NULLBUF);
- sendupdate (tbp, 1, addr);
- ++Rspf_stat.outpolls;
- return;
- }
- } else {
- rr = (struct rspfrouter *) callocw (1, sizeof (struct rspfrouter));
-
- rr->next = Rspfrouters;
- Rspfrouters = rr;
- }
- free_p (rr->data);
- rr->data = bp;
- rr->subseq = (char) nodeh.subseq;
- rr->time = secclock ();
- rr->sent = 0;
- makeroutes ();
- return;
- }
-
-
-
- /* Return the matching RSPF route entry for addr (in host order) */
- static struct rspfrouter *
- rr_lookup (uint32 addr)
- {
- struct rspfrouter *rr;
-
- for (rr = Rspfrouters; rr != NULLRROUTER; rr = rr->next)
- /* this assumes that the first word of the header is the address */
- if (rr->data != NULLBUF && get32 ((char *) rr->data->data) == addr)
- return rr;
- return NULLRROUTER;
- }
-
-
-
- /* Delete the route entry for address addr */
- static void
- rr_delete (uint32 addr)
- {
- struct rspfrouter *rr, *prev = NULLRROUTER;
-
- for (rr = Rspfrouters; rr != NULLRROUTER; prev = rr, rr = rr->next)
- /* this assumes that the first word of the header is the address */
- if (rr->data != NULLBUF && get32 ((char *) rr->data->data) == addr) {
- if (prev != NULLRROUTER)
- prev->next = rr->next;
- else
- Rspfrouters = rr->next;
- free_p (rr->data);
- free ((char *) rr);
- return;
- }
- }
-
-
-
- /* Handle incoming partial routing updates. Adjacencies from bp will be
- * merged into rr->data
- */
- static void
- partialupdate (
- struct rspfrouter *rr, /* current node entry in routing table */
- struct mbuf *bp /* data packet, starting with node header */
- ) {
- struct rspflinkh linkh, rlinkh;
- struct rspfnodeh rnodeh;
- struct mbuf *wbp, *tbp, *tmp, *b;
- int adjcnt = 0, radjcnt, rlinkcnt = 0, bits, rbits, added = 0;
- uint32 addr, raddr;
-
- rlinkh.adjn = 0;
- rr->time = secclock ();
- rr->sent = 0;
- /* Make a working copy of the stored routing update */
- if (dup_p (&wbp, rr->data, 0, len_p (rr->data)) != len_p (rr->data)) {
- free_p (wbp);
- free_p (bp);
- return;
- }
- (void) ntohrspfnode (&rnodeh, &wbp);
- (void) pullup (&bp, (unsigned char *)0, RSPFNODELEN); /* Strip off the node header */
- while (len_p (bp) > 0)
- if (adjcnt == 0) {
- if (ntohrspflink (&linkh, &bp) == -1) {
- free_p (wbp);
- free_p (bp);
- return;
- }
- adjcnt = linkh.adjn;
- } else {
- bits = PULLCHAR (&bp); /*lint !e506 * get one adjacency to merge */
- if (pullup (&bp, (unsigned char *) &addr, 4) != 4) {
- free_p (wbp);
- free_p (bp);
- return;
- }
- addr = get32 ((char *) &addr); /* convert to host order */
- --adjcnt;
- radjcnt = 0;
- b = tbp = NULLBUF;
- for ( ; ; ) { /* search through stored update */
- if (radjcnt == 0 || len_p (wbp) == 0) {
- if (tbp != NULLBUF) {
- rlinkh.adjn -= uchar(radjcnt);
- tmp = htonrspflink (&rlinkh, tbp);
- ++rlinkcnt;
- append (&b, tmp);
- tbp = NULLBUF;
- }
- if (len_p (wbp) == 0)
- break;
- }
- if (radjcnt == 0) {
- (void) ntohrspflink (&rlinkh, &wbp);
- radjcnt = rlinkh.adjn;
- if (rlinkh.horizon == linkh.horizon && rlinkh.cost ==
- linkh.cost && rlinkh.erp == linkh.erp) { /*lint !e644 */
- pushadj (&tbp, addr, bits);
- ++rlinkh.adjn;
- added = 1;
- }
- } else {
- rbits = PULLCHAR (&wbp); /*lint !e506 */
- raddr = pull32 (&wbp);
- --radjcnt;
- if (bits != rbits || addr != raddr)
- pushadj (&tbp, raddr, rbits); /* Put it back */
- else
- --rlinkh.adjn; /* deleted one adjacency */
- }
- }
- wbp = b;/* wbp now keeps link headers and adjacencies */
- if (linkh.cost < 255 && !added) { /* Append the new link */
- ++rnodeh.links; /* We will add one extra link */
- tmp = ambufw (5);
- *tmp->data = uchar(bits);
- (void) put32 (tmp->data + 1, addr);
- tmp->cnt = tmp->size;
- tbp = htonrspflink (&linkh, tmp);
- append (&wbp, tbp);
- }
- added = 0;
- }
- free_p (rr->data);
- rnodeh.links = uchar(rlinkcnt);
- rr->data = htonrspfnode (&rnodeh, wbp);
- }
-
-
-
- /* The shortest path first algorithm */
- static void
- makeroutes (void)
- {
- int bits, i, low, adjcnt;
- struct mbuf *bp;
- struct route *rp, *rp2, *saved[HASHMOD];
- struct rspfadj *adj, *lowadj, *gateway = (struct rspfadj *)0;
- unsigned char *lowp, *r;
- uint32 lowaddr;
- struct rspflinkh linkh;
- struct rspfrouter *rr, *rrprev;
-
- if (Keeprouter) /* if false, purge unreachable router entries */
- --Keeprouter;
- /* Before we change anything in the routing table, we have to save
- * each local adjacencies riface pointer
- */
- for (adj = Adjs; adj != NULLADJ; adj = adj->next)
- adj->scratch = (void *) rtif_lookup (adj->addr);
- /* Remove all non-manual routes */
- for (bits = 1; bits <= 32; bits++)
- for (i = 0; i < HASHMOD; i++)
- for (rp = Routes[bits - 1][i]; rp != NULLROUTE; rp = rp2) {
- rp2 = rp->next; /* BIG BUG FIX -- sm6rpz */
- if (dur_timer (&rp->timer) != 0)
- (void) rt_drop (rp->target, (unsigned) bits);
- /* rp will be undefined here if(dur_timer(&rp->timer) */
- }
- if (rp)
- (void) rt_drop (rp->target, (unsigned) bits);
-
- if ((rp = rt_blookup (0, 0)) != NULLROUTE && dur_timer (&rp->timer) != 0)
- (void) rt_drop (0, 0); /* delete non-manual default route */
-
- /* Temporarily remove all 32-bit specific manual routes. This will make
- * it possible to prevent loops in findlowroute()
- */
- for (i = 0; i < HASHMOD; i++) {
- saved[i] = Routes[31][i];
- Routes[31][i] = NULLROUTE;
- }
-
- for ( ; ; ) {
- lowadj = NULLADJ;
- lowp = (unsigned char *)0;
- low = 255;
- for (adj = Adjs; adj != NULLADJ; adj = adj->next) {
- if (adj->scratch == NULL)
- continue; /* skip unreachable adjacency */
- if (!adj->added) {
- if (adj->cost <= low) {
- low = adj->cost;
- lowadj = adj;
- lowp = (unsigned char *)0;
- }
- } else if ((r = (unsigned char *) findlowroute (adj->addr, &low, adj->cost, &lowaddr, &bits))
- != (unsigned char *)0) {
- lowp = r;
- gateway = adj;
- lowadj = NULLADJ;
- }
- }
- if (lowadj != NULLADJ) {
- lowadj->added++;
- rp = rt_add (lowadj->addr, 32, 0,
- ((struct rspfiface *) lowadj->scratch)->iface,
- (int32) lowadj->cost, 0, 0);
- /* set the timer to a dummy value. This makes it possible to
- * distinguish between manual and RSPF-generated routes.
- * The timer is never started however since RSPF handles the
- * expiration of routes itself.
- */
- if (rp)
- set_timer (&rp->timer, MSPTICK);
- continue;
- }
- if (lowp != (unsigned char *)0) {
- /* Check if we already have this one */
- rp = rt_blookup (lowaddr, (unsigned) bits); /*lint !e644 */
- if ((rp == NULLROUTE || (rp != NULLROUTE &&
- rp->metric > (int32) low)) && !ismyaddr (lowaddr)) {
- /* This is a new route, or a route with strict lower cost than
- * the previous route (possible only if it was manual)
- */
- if (gateway)
- rp = rt_add (lowaddr, (unsigned) bits, gateway->addr,
- ((struct rspfiface *) gateway->scratch)->iface,
- (int32) low, 0, 0);
- if (rp)
- set_timer (&rp->timer, MSPTICK); /* a dummy value */
- }
- *lowp |= 128; /* mark the route as added in any case */
- } else
- break; /* no more routes */
- }
-
- /* Add the saved 32 bit routes, if there isn't now a better route */
- for (i = 0; i < HASHMOD; i++) {
- rp = saved[i];
- while (rp != NULLROUTE) {
- rp2 = rt_blookup (rp->target, 32);
- if (rp2 == NULLROUTE || (rp2 != NULLROUTE && rp2->metric >= rp->metric)) {
- rp2 = rt_add (rp->target, 32, rp->gateway, rp->iface, rp->metric,
- 0, rp->flags & RTPRIVATE);
- rp2->uses = rp->uses;
- }
- rp2 = rp->next;
- stop_timer (&rp->timer); /* Stop timer before free() -- KZ1F */
- free ((char *) rp);
- rp = rp2;
- }
- }
-
- /* Reset all flags */
- for (adj = Adjs; adj != NULLADJ; adj = adj->next) {
- adj->added = 0;
- adj->scratch = NULL;
- }
-
- for (rr = Rspfrouters; rr != NULLRROUTER; rr = rr->next) {
- i = len_p (rr->data) - RSPFNODELEN;
- /* jump past the node header */
- if (dup_p (&bp, rr->data, RSPFNODELEN, (int16) i) != i) {
- free_p (bp);
- continue;
- }
- adjcnt = 0;
- while (i > 0) {
- if (adjcnt) {
- if (!Keeprouter && (*bp->data & 128) == 0) {
- /* This router has an adjacency that was not added. That
- * means that the router is unreachable. Mark the
- * stored routing update for deletion.
- */
- free_p (bp);
- free_p (rr->data);
- rr->data = NULLBUF; /* indicates disposal */
- break;
- }
- *bp->data &= ~128; /* Clear the "added" bit */
- (void) pullup (&bp, (unsigned char *)0, 5);
- i -= 5;
- --adjcnt;
- continue;
- }
- (void) ntohrspflink (&linkh, &bp);
- adjcnt = linkh.adjn;
- i -= RSPFLINKLEN;
- }
- }
-
- if (Keeprouter) /* nothing more to do */
- return;
- /* Delete any routers that were discovered as being unreachable */
- rrprev = NULLRROUTER;
- rr = Rspfrouters;
- for ( ; ; ) {
- for (rrprev = NULLRROUTER, rr = Rspfrouters; rr != NULLRROUTER;
- rrprev = rr, rr = rr->next)
- if (rr->data == NULLBUF) {
- if (rrprev != NULLRROUTER)
- rrprev->next = rr->next;
- else
- Rspfrouters = rr->next;
- free ((char *) rr);
- break;
- }
- if (rr == NULLRROUTER)
- break;
- }
- }
-
-
-
- /* Find a route from addr with the lowest cost. Returns a pointer to the
- * buffer that keeps the significant bit count of the selected route.
- */
- static char *
- findlowroute (
- uint32 addr, /* The node whose routes will be examined */
- int *low, /* Lowest cost so far */
- int add, /* Cost of this node */
- uint32 *resaddr, /* Resulting route stored here */
- int *resbits /* Significant bits of resulting route */
- ) {
- struct mbuf *bp;
- struct rspfrouter *rr;
- struct rspflinkh linkh;
- struct route *rp;
- char *r, *retval = NULLCHAR;
- int adjcnt = 0;
-
- linkh.cost = 0;
- if ((rr = rr_lookup (addr)) == NULLRROUTER)
- return NULLCHAR;
- if ((rp = rt_blookup (addr, 32)) != NULLROUTE && rp->metric < add)
- return NULLCHAR;/* already added this one, no loops thanks */
- if (dup_p (&bp, rr->data, RSPFNODELEN, len_p (rr->data) - RSPFNODELEN) !=
- len_p (rr->data) - RSPFNODELEN) {
- free_p (bp);
- return NULLCHAR;
- }
- while (len_p (bp) > 0) {
- if (adjcnt) {
- if (*bp->data & 128) {
- (void) PULLCHAR (&bp); /*lint !e506 */
- if ((r = findlowroute (pull32 (&bp), low, add + linkh.cost, resaddr,
- resbits)) != NULLCHAR)
- retval = r;
- } else {
- *low = add + linkh.cost;
- retval = (char *) bp->data;
- *resbits = PULLCHAR (&bp); /*lint !e506 */
- *resaddr = pull32 (&bp);
- (void) pullup (&bp, (unsigned char *)0, (int16) (5 * (adjcnt - 1)));
- adjcnt = 1; /* No need to check the rest of this link */
- }
- --adjcnt;
- continue;
- }
- (void) ntohrspflink (&linkh, &bp);
- if ((add + linkh.cost) <= *low)
- adjcnt = linkh.adjn;
- else
- (void) pullup (&bp, (unsigned char *)0, 5 * linkh.adjn);
- }
- return retval;
- }
-
-
-
- #ifndef AX25
- /*
- * Dummy stub for RSPF if AX25 is not configured.
- */
- static struct lq *
- al_lookup (struct iface *ifp, char *addr, int sort)
- {
- return NULLLQ;
- }
- #endif /* AX25 */
-
- #endif /* RSPF */
-